package org.example.utils;
import io.minio.MinioClient;
import io.minio.ObjectStat;
import io.minio.Result;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriUtils;

@Slf4j
@Component
public class MinioUtils {

  @Autowired private MinioClient minioClient;

  @Value(value = "${minio.bucket}")
  private String bucket;

  @Value(value = "${minio.url}")
  private String url;

  /** 上传 */
  public String putObject(MultipartFile multipartFile) {
    // bucket 不存在，创建
    try {
      if (!minioClient.bucketExists(this.bucket)) {
        minioClient.makeBucket(this.bucket);
      }
    } catch (Exception e) {
      log.error("Failed to create bucket: {}", this.bucket);
      throw new RuntimeException("Failed to create bucket", e); // 抛出更具体的异常
    }

    // 上传文件的名称
    String fileName = System.currentTimeMillis() + "_" +multipartFile.getOriginalFilename();
    try (InputStream inputStream = multipartFile.getInputStream()) {
      minioClient.putObject(this.bucket, fileName, inputStream, multipartFile.getContentType());
      log.info("File {} uploaded successfully to bucket {}", fileName, this.bucket);
      // 返回访问路径
      return fileName;
    } catch (Exception e) {
      log.error("Failed to upload file {} to bucket {}", fileName, this.bucket, e);
      throw new RuntimeException("Failed to upload file", e); // 抛出更具体的异常
    }
  }

  /** 文件下载 */
  public void download(String fileName, HttpServletResponse response) throws IOException {
    if(fileName == null){
      throw new RuntimeException("文件名不能为空！");
    }
    InputStream inputStream = null;
    try {
      ObjectStat stat = minioClient.statObject(bucket, fileName);
      inputStream = minioClient.getObject(bucket, fileName);
      response.setContentType(stat.contentType());
      response.setCharacterEncoding("UTF-8");
      response.setHeader(
          "Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
      IOUtils.copy(inputStream, response.getOutputStream());
    } catch (Exception e) {
      log.error("MinIO文件下载异常：{}", e);
      throw new RuntimeException("MinIO文件下载失败", e);
    } finally {
      if (inputStream != null){
        inputStream.close();
      }
    }
  }

  /**
   * 根据 名称获取完整路径
   * @param fileName 文件名
   * @return
   */
  public String getUrl(String fileName){
    return this.url + UriUtils.encode(fileName, StandardCharsets.UTF_8);
  }

  /**
   * 列出所有存储桶名称
   *
   * @return
   * @throws Exception
   */
  public List<String> listBucketNames() throws Exception {
    List<Bucket> bucketList = listBuckets();
    List<String> bucketListName = new ArrayList<>();
    for (Bucket bucket : bucketList) {
      bucketListName.add(bucket.name());
    }
    return bucketListName;
  }

  /**
   * 查看所有桶
   *
   * @return
   * @throws Exception
   */
  public List<Bucket> listBuckets() throws Exception {
    return minioClient.listBuckets();
  }

  /**
   * 检查存储桶是否存在
   *
   * @param bucketName
   * @return
   * @throws Exception
   */
  public boolean bucketExists(String bucketName) throws Exception {
    boolean flag = minioClient.bucketExists(bucketName);
    if (flag) {
      return true;
    }
    return false;
  }

  /**
   * 创建存储桶
   *
   * @param bucketName
   * @return
   * @throws Exception
   */
  public boolean makeBucket(String bucketName) throws Exception {
    boolean flag = bucketExists(bucketName);
    if (!flag) {
      minioClient.makeBucket(bucketName);
      return true;
    } else {
      return false;
    }
  }

  /**
   * 删除桶
   *
   * @param bucketName
   * @return
   * @throws Exception
   */
  public boolean removeBucket(String bucketName) throws Exception {
    boolean flag = bucketExists(bucketName);
    if (flag) {
      Iterable<Result<Item>> myObjects = listObjects(bucketName);
      for (Result<Item> result : myObjects) {
        Item item = result.get();
        // 有对象文件，则删除失败
        if (item.size() > 0) {
          return false;
        }
      }
      // 删除存储桶，注意，只有存储桶为空时才能删除成功。
      minioClient.removeBucket(bucketName);
      flag = bucketExists(bucketName);
      if (!flag) {
        return true;
      }
    }
    return false;
  }

  /**
   * 列出存储桶中的所有对象
   *
   * @param bucketName 存储桶名称
   * @return
   * @throws Exception
   */
  public Iterable<Result<Item>> listObjects(String bucketName) throws Exception {
    boolean flag = bucketExists(bucketName);
    if (flag) {
      return minioClient.listObjects(bucketName);
    }
    return null;
  }

  /**
   * 列出存储桶中的所有对象名称
   *
   * @param bucketName 存储桶名称
   * @return
   * @throws Exception
   */
  public List<String> listObjectNames(String bucketName) throws Exception {
    List<String> listObjectNames = new ArrayList<>();
    boolean flag = bucketExists(bucketName);
    if (flag) {
      Iterable<Result<Item>> myObjects = listObjects(bucketName);
      for (Result<Item> result : myObjects) {
        Item item = result.get();
        listObjectNames.add(item.objectName());
      }
    }
    return listObjectNames;
  }

  /**
   * 删除一个对象
   *
   * @param bucketName 存储桶名称
   * @param objectName 存储桶里的对象名称
   * @throws Exception
   */
  public boolean removeObject(String bucketName, String objectName) throws Exception {
    boolean flag = bucketExists(bucketName);
    if (flag) {
      List<String> objectList = listObjectNames(bucketName);
      for (String s : objectList) {
        if (s.equals(objectName)) {
          minioClient.removeObject(bucketName, objectName);
          return true;
        }
      }
    }
    return false;
  }

  /**
   * 文件访问路径
   *
   * @param bucketName 存储桶名称
   * @param objectName 存储桶里的对象名称
   * @return
   * @throws Exception
   */
  public String getObjectUrl(String bucketName, String objectName) throws Exception {
    boolean flag = bucketExists(bucketName);
    String url = "";
    if (flag) {
      url = minioClient.getObjectUrl(bucketName, objectName);
    }
    return url;
  }
}
